package cn.com.anypay.manager.common.aspect;

import cn.com.anypay.manager.common.utils.AnyJsonUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.MDC;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.multipart.MultipartFile;

import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
import java.util.Arrays;
import java.util.UUID;

/**
 * 日志切面
 * 自动记录控制器方法的请求和响应信息
 */
@Aspect
@Component
public class LoggingAspect {

    private static final Logger logger = LoggerFactory.getLogger(LoggingAspect.class);

    /**
     * 定义切点：所有Controller中的公共方法
     * 匹配以Controller结尾的所有类的公共方法
     */
    @Pointcut("execution(public * cn.com.anypay.manager..*Controller.*(..))")
    public void controllerMethods() {}

    /**
     * 环绕通知：记录方法执行前后的日志
     */
    @Around("controllerMethods()")
    public Object logExecutionTime(ProceedingJoinPoint joinPoint) throws Throwable {
        long startTime = System.currentTimeMillis();

        // 生成traceId
        String traceId = generateTraceId();
        MDC.put("traceId", traceId);

        // 获取请求信息
        HttpServletRequest request = getCurrentRequest();
        String className = joinPoint.getTarget().getClass().getSimpleName();
        String methodName = joinPoint.getSignature().getName();
        Object[] args = joinPoint.getArgs();

        try {
            // 记录请求开始日志
            logRequestStart(request, className, methodName, args, traceId);

            // 执行目标方法
            Object result = joinPoint.proceed();

            // 计算执行时间
            long executionTime = System.currentTimeMillis() - startTime;

            // 记录请求完成日志
            logRequestEnd(className, methodName, result, executionTime, traceId);

            return result;

        } catch (Exception e) {
            // 计算执行时间
            long executionTime = System.currentTimeMillis() - startTime;

            // 记录异常日志
            logRequestError(className, methodName, e, executionTime, traceId);

            throw e;
        } finally {
            // 清理MDC
            MDC.remove("traceId");
        }
    }

    /**
     * 记录请求开始日志
     */
    private void logRequestStart(HttpServletRequest request, String className, String methodName,
                                Object[] args, String traceId) {
        if (request != null) {
            logger.info("=== 请求开始 [{}] ===", traceId);
            logger.info("请求URL: {} {}", request.getMethod(), request.getRequestURL());
            logger.info("请求IP: {}", getClientIpAddress(request));
            logger.info("用户代理: {}", request.getHeader("User-Agent"));
            logger.info("执行方法: {}.{}", className, methodName);

            // 记录请求参数（过滤敏感信息）
            if (args != null && args.length > 0) {
                String params = AnyJsonUtils.toJsonString(filterSensitiveData(args));
                logger.info("请求参数: {}", params);
            }
        }
    }

    /**
     * 记录请求完成日志
     */
    private void logRequestEnd(String className, String methodName, Object result,
                              long executionTime, String traceId) {
        logger.info("=== 请求完成 [{}] ===", traceId);
        logger.info("执行方法: {}.{}", className, methodName);
        logger.info("执行时间: {}ms", executionTime);

        // 记录响应结果（可能很大，可以选择性记录）
        if (result != null && executionTime > 1000) { // 只记录执行时间超过1秒的响应
            logger.info("响应结果: {}", AnyJsonUtils.toJsonString(result));
        }
    }

    /**
     * 记录异常日志
     */
    private void logRequestError(String className, String methodName, Exception e,
                                long executionTime, String traceId) {
        logger.error("=== 请求异常 [{}] ===", traceId);
        logger.error("执行方法: {}.{}", className, methodName);
        logger.error("执行时间: {}ms", executionTime);
        logger.error("异常信息: {}", e.getMessage(), e);
    }

    /**
     * 生成traceId
     */
    private String generateTraceId() {
        return UUID.randomUUID().toString().replace("-", "").substring(0, 16);
    }

    /**
     * 获取当前请求
     */
    private HttpServletRequest getCurrentRequest() {
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        return attributes != null ? attributes.getRequest() : null;
    }

    /**
     * 获取客户端IP地址
     */
    private String getClientIpAddress(HttpServletRequest request) {
        String xForwardedFor = request.getHeader("X-Forwarded-For");
        if (xForwardedFor != null && !xForwardedFor.isEmpty() && !"unknown".equalsIgnoreCase(xForwardedFor)) {
            return xForwardedFor.split(",")[0];
        }

        String xRealIp = request.getHeader("X-Real-IP");
        if (xRealIp != null && !xRealIp.isEmpty() && !"unknown".equalsIgnoreCase(xRealIp)) {
            return xRealIp;
        }

        return request.getRemoteAddr();
    }

    /**
     * 过滤敏感数据
     */
    private Object[] filterSensitiveData(Object[] args) {
        return Arrays.stream(args)
                .map(arg -> {
                    if (arg == null) return null;

                    // 处理HttpServletRequest类型，避免序列化异常
                    if (arg instanceof HttpServletRequest) {
                        HttpServletRequest req = (HttpServletRequest) arg;
                        return String.format("[HttpServletRequest: method=%s, uri=%s]",
                                req.getMethod(), req.getRequestURI());
                    }

                    // 处理其他Servlet相关对象
                    if (arg instanceof ServletRequest ||
                        arg instanceof ServletResponse ||
                        arg instanceof HttpServletResponse) {
                        return "[ServletObject: " + arg.getClass().getSimpleName() + "]";
                    }

                    // 处理MultipartFile类型，避免序列化异常
                    if (arg instanceof MultipartFile) {
                        MultipartFile file = (MultipartFile) arg;
                        return String.format("[MultipartFile: name=%s, size=%d, contentType=%s]",
                                file.getOriginalFilename(), file.getSize(), file.getContentType());
                    }

                    String argStr = arg.toString();
                    // 过滤密码、token等敏感信息
                    if (argStr.contains("password") || argStr.contains("token") || argStr.contains("secret")) {
                        return "[FILTERED]";
                    }
                    return arg;
                })
                .toArray();
    }
}